package com.hqd.ch03.v46.core.annotation;


import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 组合注解接口
 *
 * @param <A>
 */

public interface MergedAnnotation<A extends Annotation> {

    /**
     * 注解默认属性
     */
    String VALUE = "value";

    /**
     * 缺失注解
     */
    static <A extends Annotation> MergedAnnotation<A> missing() {
        return MissingMergedAnnotation.getInstance();
    }

    /**
     * 创建组合注解,基于已有注解
     */
    static <A extends Annotation> MergedAnnotation<A> from(A annotation) {
        return from(null, annotation);
    }

    /**
     * 创建组合注解，仅用于日志
     */
    static <A extends Annotation> MergedAnnotation<A> from(Object source, A annotation) {
        return TypeMappedAnnotation.from(source, annotation);
    }

    /**
     * 创建组合注解
     *
     * @param annotationType
     * @param <A>
     * @return
     */
    static <A extends Annotation> MergedAnnotation<A> of(Class<A> annotationType) {
        return of(null, annotationType, null);
    }

    static <A extends Annotation> MergedAnnotation<A> of(
            Class<A> annotationType, Map<String, ?> attributes) {

        return of(null, annotationType, attributes);
    }

    static <A extends Annotation> MergedAnnotation<A> of(
            AnnotatedElement source, Class<A> annotationType, Map<String, ?> attributes) {

        return of(null, source, annotationType, attributes);
    }

    static <A extends Annotation> MergedAnnotation<A> of(
            ClassLoader classLoader, Object source,
            Class<A> annotationType, Map<String, ?> attributes) {
        return TypeMappedAnnotation.of(classLoader, source, annotationType, attributes);
    }

    Class<A> getType();

    boolean isPresent();

    boolean isDirectlyPresent();

    boolean isMetaPresent();

    int getDistance();

    int getAggregateIndex();


    Object getSource();

    MergedAnnotation<?> getMetaSource();

    MergedAnnotation<?> getRoot();

    List<Class<? extends Annotation>> getMetaTypes();

    /**
     * 是否不存在默认值
     **/
    boolean hasNonDefaultValue(String attributeName);

    /**
     * 是否存在默认值
     **/
    boolean hasDefaultValue(String attributeName) throws NoSuchElementException;

    byte getByte(String attributeName) throws NoSuchElementException;

    byte[] getByteArray(String attributeName) throws NoSuchElementException;

    boolean getBoolean(String attributeName) throws NoSuchElementException;

    boolean[] getBooleanArray(String attributeName) throws NoSuchElementException;

    char getChar(String attributeName) throws NoSuchElementException;

    char[] getCharArray(String attributeName) throws NoSuchElementException;

    short getShort(String attributeName) throws NoSuchElementException;

    short[] getShortArray(String attributeName) throws NoSuchElementException;

    int getInt(String attributeName) throws NoSuchElementException;

    int[] getIntArray(String attributeName) throws NoSuchElementException;

    long getLong(String attributeName) throws NoSuchElementException;

    long[] getLongArray(String attributeName) throws NoSuchElementException;

    double getDouble(String attributeName) throws NoSuchElementException;

    double[] getDoubleArray(String attributeName) throws NoSuchElementException;

    float getFloat(String attributeName) throws NoSuchElementException;

    float[] getFloatArray(String attributeName) throws NoSuchElementException;

    String getString(String attributeName) throws NoSuchElementException;

    String[] getStringArray(String attributeName) throws NoSuchElementException;

    Class<?> getClass(String attributeName) throws NoSuchElementException;

    Class<?>[] getClassArray(String attributeName) throws NoSuchElementException;

    <E extends Enum<E>> E getEnum(String attributeName, Class<E> type) throws NoSuchElementException;

    <E extends Enum<E>> E[] getEnumArray(String attributeName, Class<E> type) throws NoSuchElementException;

    <T extends Annotation> MergedAnnotation<T> getAnnotation(String attributeName, Class<T> type)
            throws NoSuchElementException;

    <T extends Annotation> MergedAnnotation<T>[] getAnnotationArray(String attributeName, Class<T> type)
            throws NoSuchElementException;

    Optional<Object> getValue(String attributeName);

    <T> Optional<T> getValue(String attributeName, Class<T> type);

    Optional<Object> getDefaultValue(String attributeName);

    <T> Optional<T> getDefaultValue(String attributeName, Class<T> type);

    MergedAnnotation<A> filterDefaultValues();

    MergedAnnotation<A> filterAttributes(Predicate<String> predicate);

    MergedAnnotation<A> withNonMergedAttributes();

    AnnotationAttributes asAnnotationAttributes(Adapt... adaptations);

    Map<String, Object> asMap(Adapt... adaptations);

    <T extends Map<String, Object>> T asMap(Function<MergedAnnotation<?>, T> factory, Adapt... adaptations);

    A synthesize() throws NoSuchElementException;

    Optional<A> synthesize(Predicate<? super MergedAnnotation<A>> condition) throws NoSuchElementException;


    /**
     * 适配器
     */
    enum Adapt {

        /**
         * 将类或类数组属性调整为字符串。
         */
        CLASS_TO_STRING,

        /**
         * 注解转map
         */
        ANNOTATION_TO_MAP;

        public static Adapt[] values(boolean classToString, boolean annotationsToMap) {
            EnumSet<Adapt> result = EnumSet.noneOf(Adapt.class);
            addIfTrue(result, Adapt.CLASS_TO_STRING, classToString);
            addIfTrue(result, Adapt.ANNOTATION_TO_MAP, annotationsToMap);
            return result.toArray(new Adapt[0]);
        }

        private static <T> void addIfTrue(Set<T> result, T value, boolean test) {
            if (test) {
                result.add(value);
            }
        }

        protected final boolean isIn(Adapt... adaptations) {
            for (Adapt candidate : adaptations) {
                if (candidate == this) {
                    return true;
                }
            }
            return false;
        }
    }
}
